using System;
using System.Collections.Generic;
using System.Text;
using Barrage.Global;
using Barrage.Global.Vertex;
using SlimDX.Direct3D9;
using SlimDX;


namespace Barrage.Meshes
{
    /// <summary>
    /// PostprocessMesh draws a rectangle that, used in conjuction with a Scene2D, will have the exact size of the render target
    /// This is useful for applying postprocess effects with a shader
    /// </summary>
    public class PostprocessMesh : Barrage.Mesh
    {
        private static SlimDX.Direct3D9.VertexBuffer planeBuffer = null;

        private static void initializeBuffer()
        {
            planeBuffer = new VertexBuffer(Engine.Device,VertexPositionUV.SizeBytes*4,Usage.WriteOnly,VertexPositionUV.Format,Pool.Managed);
            DataStream stream = planeBuffer.Lock(0,0,LockFlags.None);
            VertexPositionUV []vertices=new VertexPositionUV[4];
            vertices[0].Position = new Vector3(0, 0, 0); vertices[0].UV = new Vector2(0, 1);
            vertices[1].Position = new Vector3(0, 1, 0); vertices[1].UV = new Vector2(0, 0);
            vertices[2].Position=new Vector3(1,0,0);vertices[2].UV=new Vector2(1,1);
            vertices[3].Position = new Vector3(1, 1, 0); vertices[3].UV = new Vector2(1, 0);
            stream.WriteRange(vertices);
            planeBuffer.Unlock();
            Engine.RegisterDisposeHandler(new EngineDisposeHandler(DisposeBuffer));
        }

        private static void DisposeBuffer()
        {
            if (planeBuffer != null)
            {
                planeBuffer.Dispose();
                planeBuffer = null;
            }
        }

        /// <summary>
        /// Inits the Postprocess mesh with the specified texture as source
        /// </summary>
        /// <param name="source">Texture that will be drawn</param>
        public PostprocessMesh(BaseTexture source)
        {
            if (planeBuffer == null)
                initializeBuffer();
            Material m = new Material();
            m.Texture = source;
            materials.Add(m);
        }

        /// <summary>
        /// \internal Renders the mesh
        /// </summary>
        /// <param name="item">Item that is being rendered</param>        
        public override void Render(Item item)
        {
            RenderStats.RenderCalls++;
            shader.BeginRender(item, materials[0]);
            Engine.Device.VertexFormat = VertexPositionUV.Format;
            Engine.Device.SetStreamSource(0, planeBuffer, 0, VertexPositionUV.SizeBytes);
            int passNumber = shader.PassNumber(materials[0]);
            for (int j = 0; j < passNumber; j++)
            {
                shader.BeginPass(j);
                Engine.Device.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);
                shader.EndPass();
            } 
            shader.EndRender();

            NLog.LogManager.GetLogger("Barrage::Scene::Graphics3D::PostprocessMesh").Debug("Rendering Cube");
        }
    }
}
